﻿using System;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

namespace Tk.Soc.License.Utils
{
    public static class HardwareInfoHelper
    {
        /// <summary>
        /// win环境 获取机器码
        /// </summary>
        /// <returns></returns>
        public static string GetWinHardwareInfoCode()
        {
            string cpuID = GetWinCPUID();
            string baseBoardID = GetWinBaseBoardID();
            string diskID = GetWinHardDiskID();
            return MD5(cpuID + baseBoardID + diskID);
        }

        /// <summary>
        /// Linux环境 获取机器码
        /// </summary>
        /// <returns></returns>
        public static string GetLinuxHardwareInfoCode()
        {
            string cpuID = GetLinuxCPUID();
            string baseBoardID = GetLinuxBaseBoardID();
            string diskID = GetLinuxHardDiskID();
            return MD5(cpuID + baseBoardID + diskID);
        }

        private static string GetWinCPUID()
        {
            string res = RunCommand("wmic", "CPU get ProcessorID");
            res = Regex.Replace(res, "\r|\n|\\s", "");
            Console.WriteLine("【---------------------------------------------CPU序列号-------------------------------------------------】：");
            Console.WriteLine(res);
            return res;
        }

        /// <summary>
        /// linux 获取CpuID
        /// </summary>
        /// <returns></returns>
        private static string GetLinuxCPUID()
        {
            string res = Bash("dmidecode -t 4 | grep ID | awk -F: '{print $2}'");
            Console.WriteLine("【---------------------------------------------CPU序列号-------------------------------------------------】：");
            Console.WriteLine(res);
            return res;
        }

        /// <summary>
        /// win环境 获取主板ID
        /// </summary>
        /// <returns></returns>
        private static string GetWinBaseBoardID()
        {
            string res = RunCommand("wmic", "baseboard get serialnumber");
            res = Regex.Replace(res, "\r|\n|\\s", "");
            Console.WriteLine("【-----------------------------------------------主板ID--------------------------------------------------】：");
            Console.WriteLine(res);
            return res;
        }

        /// <summary>
        /// linux环境 获取主板ID
        /// </summary>
        /// <returns></returns>
        private static string GetLinuxBaseBoardID()
        {
            string res = Bash("dmidecode -t 2 | grep 'Serial Number' | awk -F: '{print $2}'");
            Console.WriteLine("【-----------------------------------------------主板ID--------------------------------------------------】：");
            Console.WriteLine(res);
            return res;
        }

        /// <summary>
        /// linux环境 获取内存ID
        /// </summary>
        /// <returns></returns>
        private static string GetLinuxMemoryID()
        {
            string res = Bash("dmidecode -t memory | grep 'Serial Number'");
            Console.WriteLine("【-----------------------------------------------内存ID--------------------------------------------------】：");
            Console.WriteLine(res);
            return res;
        }

        /// <summary>
        /// win环境 获取BIOSID
        /// </summary>
        /// <returns></returns>
        private static string GetWinBIOSID()
        {
            string res = RunCommand("wmic", "bios get serialnumber");
            Console.WriteLine("【---------------------------------------------BIOS序列号------------------------------------------------】：");
            Console.WriteLine(res);
            return res;
        }

        /// <summary>
        /// win环境 获取硬盘ID（只取第一个）
        /// </summary>
        /// <returns></returns>
        private static string GetWinHardDiskID()
        {
            string res = RunCommand("wmic", "diskdrive where index=0 get serialnumber");
            res = Regex.Replace(res, "\r|\n|\\s", "");
            Console.WriteLine("【-----------------------------------------------硬盘ID--------------------------------------------------】：");
            Console.WriteLine(res);
            return res;
        }

        /// <summary>
        /// linux环境 获取硬盘ID（只取第一个）
        /// </summary>
        /// <returns></returns>
        private static string GetLinuxHardDiskID()
        {
            string res = Bash("fdisk -l |grep identifier|head -1 | awk -F: '{print $2}'");
            Console.WriteLine("【-----------------------------------------------硬盘ID--------------------------------------------------】：");
            Console.WriteLine(res);
            return res;
        }

        private static string RunCommand(string fileName, string arguments)
        {
            var psi = new ProcessStartInfo(fileName, arguments) { RedirectStandardOutput = true };
            psi.UseShellExecute = false;
            psi.CreateNoWindow = true;
            var proc = Process.Start(psi);
            string result = "";
            if (proc == null)
                Console.WriteLine("Can not exec" + fileName + arguments);
            else
            {
                using (var sr = proc.StandardOutput)
                {
                    while (!sr.EndOfStream)
                        result += sr.ReadLine();
                    if (!proc.HasExited)
                        proc.Kill();
                }

            }
            return result;
        }

        /// <summary>
        /// 执行linux指令
        /// </summary>
        /// <param name="cmd"></param>
        /// <returns></returns>
        private static string Bash(string cmd)
        {
            var escapedArgs = cmd.Replace("\"", "\\\"");

            var process = new Process()
            {
                StartInfo = new ProcessStartInfo
                {
                    FileName = "/bin/bash",
                    Arguments = $"-c \"{escapedArgs}\"",
                    RedirectStandardOutput = true,
                    UseShellExecute = false,
                    CreateNoWindow = true,
                }
            };
            process.Start();
            string result = process.StandardOutput.ReadToEnd();
            process.WaitForExit();
            return result;
        }

        private static string MD5(string scr)
        {
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] palindata = Encoding.Default.GetBytes(scr);
            byte[] encryptdata = md5.ComputeHash(palindata);
            return GetHexString(encryptdata);
        }

        private static string GetHexString(byte[] bt)
        {
            string s = string.Empty;
            for (int i = 0; i < bt.Length; i++)
            {
                byte b = bt[i];
                int n, n1, n2;
                n = (int)b;
                n1 = n & 15;
                n2 = (n >> 4) & 15;
                if (n2 > 9)
                    s += ((char)(n2 - 10 + (int)'A')).ToString();
                else
                    s += n2.ToString();
                if (n1 > 9)
                    s += ((char)(n1 - 10 + (int)'A')).ToString();
                else
                    s += n1.ToString();
                if ((i + 1) != bt.Length && (i + 1) % 2 == 0) s += "-";
            }
            return s;
        }

    }
}
